package com.kymatrix.mpo.plus.bpm.server.convert.task;

import com.kymatrix.mpo.plus.bpm.api.event.BpmProcessInstanceStatusEvent;
import com.kymatrix.mpo.plus.bpm.server.flowable.util.FlowableUtils;
import com.kymatrix.mpo.plus.bpm.server.model.dto.message.BpmMessageSendWhenProcessInstanceApproveReqDTO;
import com.kymatrix.mpo.plus.bpm.server.model.dto.message.BpmMessageSendWhenProcessInstanceRejectReqDTO;
import com.kymatrix.mpo.plus.bpm.server.model.entity.definition.BpmCategoryEntity;
import com.kymatrix.mpo.plus.bpm.server.model.entity.definition.BpmProcessDefinitionInfoEntity;
import com.kymatrix.mpo.plus.bpm.server.model.form.instance.QueryBpmProcessInstanceResp;
import com.kymatrix.mpo.plus.bpm.server.model.form.process.QueryBpmProcessDefinitionResp;
import com.kymatrix.mpo.plus.common.business.common.PageResp;
import com.kymatrix.mpo.plus.common.util.BeanUtils;
import com.kymatrix.mpo.plus.common.util.MapUtils;
import com.kymatrix.mpo.plus.system.api.dto.DeptmentDto;
import com.kymatrix.mpo.plus.system.api.dto.UserDto;
import java.util.List;
import java.util.Map;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.mapstruct.Mapper;

/**
 * 流程实例 Convert
 */
@Mapper
public class BpmProcessInstanceConvert {


    public static PageResp<QueryBpmProcessInstanceResp> buildProcessInstancePage(PageResp<HistoricProcessInstance> pageResult,
                                                                           Map<String, ProcessDefinition> processDefinitionMap,
                                                                           Map<String, BpmCategoryEntity> categoryMap,
                                                                           Map<String, List<Task>> taskMap,
                                                                           Map<String, UserDto> userMap,
                                                                           Map<String, DeptmentDto> deptMap) {
        PageResp<QueryBpmProcessInstanceResp> vpPageResult = new PageResp<>();
        vpPageResult.setTotal(pageResult.getTotal());
        for (HistoricProcessInstance historicProcessInstance : pageResult.getList()) {
            vpPageResult.getList().add(QueryBpmProcessInstanceResp.fromEntity(historicProcessInstance));
        }
        
        for (int i = 0; i < pageResult.getList().size(); i++) {
            QueryBpmProcessInstanceResp respVO = vpPageResult.getList().get(i);
            respVO.setStatus(FlowableUtils.getProcessInstanceStatus(pageResult.getList().get(i)));
            MapUtils.findAndThen(processDefinitionMap, respVO.getProcessDefinitionId(),
                    processDefinition -> respVO.setCategory(processDefinition.getCategory()));
            MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName()));
            respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), QueryBpmProcessInstanceResp.Task.class));
            // user
            if (userMap != null) {
                UserDto startUser = userMap.get(pageResult.getList().get(i).getStartUserId());
                if (startUser != null) {
                    respVO.setStartUser(BeanUtils.toBean(startUser, QueryBpmProcessInstanceResp.User.class));
                    MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName()));
                }
            }
        }
        return vpPageResult;
    }

    public static QueryBpmProcessInstanceResp buildProcessInstance(HistoricProcessInstance processInstance,
                                                             ProcessDefinition processDefinition,
                                                             BpmProcessDefinitionInfoEntity processDefinitionExt,
                                                             String bpmnXml,
                                                             UserDto startUser,
                                                             DeptmentDto dept) {
        QueryBpmProcessInstanceResp respVO = BeanUtils.toBean(processInstance, QueryBpmProcessInstanceResp.class);
        respVO.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance));
        respVO.setFormVariables(FlowableUtils.getProcessInstanceFormVariable(processInstance));
        // definition
        respVO.setProcessDefinition(BeanUtils.toBean(processDefinition, QueryBpmProcessDefinitionResp.class));
        copyTo(processDefinitionExt, respVO.getProcessDefinition());
        respVO.getProcessDefinition().setBpmnXml(bpmnXml);
        // user
        if (startUser != null) {
            respVO.setStartUser(BeanUtils.toBean(startUser, QueryBpmProcessInstanceResp.User.class));
            if (dept != null) {
                respVO.getStartUser().setDeptName(dept.getName());
            }
        }
        return respVO;
    }

    public static void copyTo(BpmProcessDefinitionInfoEntity from, QueryBpmProcessDefinitionResp to) {
        to.setIcon(from.getIcon());
        to.setDescription(from.getDescription());
        to.setFormType(from.getFormType());
        to.setFormId(from.getFormId());
        to.setFormConf(from.getFormConf());
        to.setFormFields(from.getFormFields());
        to.setFormCustomCreatePath(from.getFormCustomCreatePath());
        to.setFormCustomViewPath(from.getFormCustomViewPath());
    }

    public static BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, HistoricProcessInstance instance, String status) {
        return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
                .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
    }

    public static BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, String status) {;
        return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
                .setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
    }

    public static BpmMessageSendWhenProcessInstanceApproveReqDTO buildProcessInstanceApproveMessage(ProcessInstance instance) {
        return new BpmMessageSendWhenProcessInstanceApproveReqDTO()
                .setStartUserId(instance.getStartUserId())
                .setProcessInstanceId(instance.getId())
                .setProcessInstanceName(instance.getName());
    }

    public static BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) {
        return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
            .setProcessInstanceName(instance.getName())
            .setProcessInstanceId(instance.getId())
            .setReason(reason)
            .setStartUserId(instance.getStartUserId());
    }

}
